<html>
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
  <title>
   Hadoop RPC通信Client客户端的流程分析  | 数螺 | NAUT IDEA
  </title>
  <link href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet"/>
  <link href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
  <style type="text/css">
   #xmain img {
                  max-width: 100%;
                  display: block;
                  margin-top: 10px;
                  margin-bottom: 10px;
                }

                #xmain p {
                    line-height:150%;
                    font-size: 16px;
                    margin-top: 20px;
                }

                #xmain h2 {
                    font-size: 24px;
                }

                #xmain h3 {
                    font-size: 20px;
                }

                #xmain h4 {
                    font-size: 18px;
                }


                .header {
	           background-color: #0099ff;
	           color: #ffffff;
	           margin-bottom: 20px;
	        }

	        .header p {
                  margin: 0px;
                  padding: 10px 0;
                  display: inline-block;  
                  vertical-align: middle;
                  font-size: 16px;
               }

               .header a {
                 color: white;
               }

              .header img {
                 height: 25px;
              }
  </style>
  <script src="http://cdn.bootcss.com/jquery/3.0.0/jquery.min.js">
  </script>
  <script src="http://nautstatic-10007657.file.myqcloud.com/static/css/readability.min.js" type="text/javascript">
  </script>
  <script type="text/javascript">
   $(document).ready(function() {
                 var loc = document.location;
                 var uri = {
                  spec: "http://dataunion.org/3225.html",
                  host: "http://dataunion.org",
                  prePath: "http://dataunion.org",
                  scheme: "http",
                  pathBase: "http://dataunion.org/"
                 };
    
                 var documentClone = document.cloneNode(true);
                 var article = new Readability(uri, documentClone).parse();
     
                 document.getElementById("xmain").innerHTML = article.content;
                });
  </script>
  <!-- 1466461115: Accept with keywords: (title(0.2):数盟,流程,社区,Hadoop,客户端, topn(0.3):协议,社区,子类,流程,数盟,信息,行业资讯,作者,基类,数据挖掘,远程,结果,版本号,并行,参数,文章,基础架构,职业规划,数据,服务端,变量,对象,Hadoop,地址,客户端,标识,方法,用户组,模块,序列化).-->
 </head>
 <body onload="">
  <div class="header">
   <div class="container">
    <div class="row">
     <div class="col-xs-6 col-sm-6 text-left">
      <a href="/databee">
       <img src="http://nautidea-10007657.cos.myqcloud.com/logo_white.png"/>
      </a>
      <a href="/databee">
       <p>
        数螺
       </p>
      </a>
     </div>
     <div class="hidden-xs col-sm-6 text-right">
      <p>
       致力于数据科学的推广和知识传播
      </p>
     </div>
    </div>
   </div>
  </div>
  <div class="container text-center">
   <h1>
    Hadoop RPC通信Client客户端的流程分析
   </h1>
  </div>
  <div class="container" id="xmain">
   ﻿﻿
   <title>
    Hadoop RPC通信Client客户端的流程分析 | 数盟社区
   </title>
   <!-- All in One SEO Pack 2.2.7.6.2 by Michael Torbert of Semper Fi Web Design[32,73] -->
   <!-- /all in one seo pack -->
   <!--
<div align="center">
<a href="http://strata.oreilly.com.cn/hadoop-big-data-cn?cmp=mp-data-confreg-home-stcn16_dataunion_pc" target="_blank"><img src="http://dataunion.org/wp-content/uploads/2016/05/stratabj.jpg"/ ></a>
</div>
-->
   <header id="header-web">
    <div class="header-main">
     <hgroup class="logo">
      <h1>
       <a href="http://dataunion.org/" rel="home" title="数盟社区">
        <img src="http://dataunion.org/wp-content/themes/yzipi/images/logo.png"/>
       </a>
      </h1>
     </hgroup>
     <!--logo-->
     <nav class="header-nav">
      <ul class="menu" id="menu-%e4%b8%bb%e8%8f%9c%e5%8d%95">
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-71" id="menu-item-71">
        <a href="http://dataunion.org/category/events" title="events">
         活动
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22457" id="menu-item-22457">
          <a href="http://dataunion.org/2016timeline">
           2016档期
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-22459" id="menu-item-22459">
          <a href="http://dataunion.org/category/parterc">
           合作会议
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor menu-item-has-children menu-item-20869" id="menu-item-20869">
        <a href="http://dataunion.org/category/tech" title="articles">
         文章
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-20867" id="menu-item-20867">
          <a href="http://dataunion.org/category/tech/base" title="base">
           基础架构
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3302" id="menu-item-3302">
          <a href="http://dataunion.org/category/tech/ai" title="ai">
           人工智能
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3303" id="menu-item-3303">
          <a href="http://dataunion.org/category/tech/analysis" title="analysis">
           数据分析
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21920" id="menu-item-21920">
          <a href="http://dataunion.org/category/tech/dm">
           数据挖掘
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3314" id="menu-item-3314">
          <a href="http://dataunion.org/category/tech/viz" title="viz">
           可视化
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3305" id="menu-item-3305">
          <a href="http://dataunion.org/category/tech/devl" title="devl">
           编程语言
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-20876" id="menu-item-20876">
        <a href="http://dataunion.org/category/industry">
         行业
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-16328" id="menu-item-16328">
          <a href="http://dataunion.org/category/industry/case" title="case">
           行业应用
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-2112" id="menu-item-2112">
          <a href="http://dataunion.org/category/industry/demo" title="demo">
           Demo展示
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21562" id="menu-item-21562">
          <a href="http://dataunion.org/category/industry/news">
           行业资讯
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-311" id="menu-item-311">
        <a href="http://dataunion.org/category/sources" title="sources">
         资源
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20870" id="menu-item-20870">
        <a href="http://dataunion.org/category/books" title="book">
         图书
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21363" id="menu-item-21363">
        <a href="http://dataunion.org/category/training">
         课程
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-21853" id="menu-item-21853">
        <a href="http://dataunion.org/category/jobs">
         职位
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-22050" id="menu-item-22050">
          <a href="http://dataunion.org/category/career">
           职业规划
          </a>
         </li>
        </ul>
       </li>
      </ul>
     </nav>
     <!--header-nav-->
    </div>
   </header>
   <!--header-web-->
   <div id="main">
    <div id="soutab">
     <form action="http://dataunion.org/" class="search" method="get">
     </form>
    </div>
    <div id="container">
     <nav id="mbx">
      当前位置：
      <a href="http://dataunion.org">
       首页
      </a>
      &gt;
      <a href="http://dataunion.org/category/tech">
       文章
      </a>
      &gt;
      <a href="http://dataunion.org/category/tech/base">
       基础架构
      </a>
      &gt;  正文
     </nav>
     <!--mbx-->
     <article class="content">
      <header align="centre" class="contenttitle">
       <div class="mscc">
        <h1 class="mscctitle">
         <a href="http://dataunion.org/3225.html">
          Hadoop RPC通信Client客户端的流程分析
         </a>
        </h1>
        <address class="msccaddress ">
         <em>
          1,940 次阅读 -
         </em>
         <a href="http://dataunion.org/category/tech/base" rel="category tag">
          基础架构
         </a>
        </address>
       </div>
      </header>
      <div class="content-text">
       <p>
        作者：
        <a class="user_name" href="http://my.csdn.net/Androidlushangderen" target="_blank">
         Android路上的人
        </a>
       </p>
       <p>
        Hadoop的RPC的通信与其他系统的RPC通信不太一样，作者针对Hadoop的使用特点，专门的设计了一套RPC框架，这套框架个人感觉还是 有点小复杂的。所以我打算分成Client客户端和Server服务端2个模块做分析。如果你对RPC的整套流程已经非常了解的前提下，对于Hadoop 的RPC，你也一定可以非常迅速的了解的。OK，下面切入正题。
       </p>
       <p>
        Hadoop的RPC的相关代码都在
        <strong>
         org.apache.hadoop.ipc
        </strong>
        的包下，首先RPC的通信必须遵守许多的协议，其中最最基本的协议即使如下：
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /**
         </span>
        </li>
        <li>
         <span class="comment">
          * Superclass of all protocols that use Hadoop RPC.
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * Subclasses of this interface are also supposed to have
         </span>
        </li>
        <li>
         <span class="comment">
          * a static final long versionID field.
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * Hadoop RPC所有协议的基类，返回协议版本号
         </span>
        </li>
        <li>
         <span class="comment">
          */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          interface
         </span>
         VersionedProtocol {
        </li>
        <li>
        </li>
        <li class="alt">
         <span class="comment">
          /**
         </span>
        </li>
        <li>
         <span class="comment">
          * Return protocol version corresponding to protocol interface.
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * @param protocol The classname of the protocol interface
         </span>
        </li>
        <li>
         <span class="comment">
          * @param clientVersion The version of the protocol that the client speaks
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * @return the version that the server will speak
         </span>
        </li>
        <li>
         <span class="comment">
          */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          long
         </span>
         getProtocolVersion(String protocol,
        </li>
        <li>
         <span class="keyword">
          long
         </span>
         clientVersion)
         <span class="keyword">
          throws
         </span>
         IOException;
        </li>
        <li class="alt">
         }
        </li>
       </ol>
       <p>
        他是所有协议的基类，他的下面还有一堆的子类，分别对应于不同情况之间的通信，下面是一张父子类图：
       </p>
       <p>
        <a href="http://s2.51cto.com/wyfs02/M02/54/83/wKioL1SFTD3w1XAnAAN6lfc-_N4161.jpg" target="_blank">
         <img src="http://s2.51cto.com/wyfs02/M02/54/83/wKioL1SFTD3w1XAnAAN6lfc-_N4161.jpg"/>
        </a>
       </p>
       <p>
        顾名思义，只有客户端和服务端遵循相同的版本号，才能进行通信。
       </p>
       <p>
        RPC客户端的所有相关操作都被封装在了一个叫Client.java的文件中:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /** A client for an IPC service.  IPC calls take a single {@link Writable} as a
         </span>
        </li>
        <li>
         <span class="comment">
          * parameter, and return a {@link Writable} as their value.  A service runs on
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * a port and is defined by a parameter class and a value class.
         </span>
        </li>
        <li>
         <span class="comment">
          * RPC客户端类
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * @see Server
         </span>
        </li>
        <li>
         <span class="comment">
          */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          class
         </span>
         Client {
        </li>
        <li>
        </li>
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          static
         </span>
         <span class="keyword">
          final
         </span>
         Log LOG =
        </li>
        <li>
         LogFactory.getLog(Client.
         <span class="keyword">
          class
         </span>
         );
        </li>
        <li class="alt">
         <span class="comment">
          //客户端到服务端的连接
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         Hashtable&lt;ConnectionId, Connection&gt; connections =
        </li>
        <li class="alt">
         <span class="keyword">
          new
         </span>
         Hashtable&lt;ConnectionId, Connection&gt;();
        </li>
        <li>
        </li>
        <li class="alt">
         <span class="comment">
          //回调值类
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         Class&lt;?
         <span class="keyword">
          extends
         </span>
         Writable&gt; valueClass;
         <span class="comment">
          // class of call values
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //call回调id的计数器
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         counter;
         <span class="comment">
          // counter for call ids
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //原子变量判断客户端是否还在运行
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         AtomicBoolean running =
         <span class="keyword">
          new
         </span>
         AtomicBoolean(
         <span class="keyword">
          true
         </span>
         );
         <span class="comment">
          // if client runs
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          final
         </span>
         <span class="keyword">
          private
         </span>
         Configuration conf;
        </li>
        <li>
        </li>
        <li class="alt">
         <span class="comment">
          //socket工厂，用来创建socket
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         SocketFactory socketFactory;
         <span class="comment">
          // how to create sockets
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         refCount =
         <span class="number">
          1
         </span>
         ;
        </li>
        <li>
         ……
        </li>
       </ol>
       <p>
        从代码中明显的看到，这里存在着一个类似于connections连接池的东西，其实这暗示着连接是可以被复用的，在hashtable中，与每个Connecttion连接的对应的是一个ConnectionId，显然这里不是一个Long类似的数值:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /**
         </span>
        </li>
        <li>
         <span class="comment">
          * This class holds the address and the user ticket. The client connections
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * to servers are uniquely identified by &lt;remoteAddress, protocol, ticket&gt;
         </span>
        </li>
        <li>
         <span class="comment">
          * 连接的唯一标识，主要通过&lt;远程地址，协议类型，用户组信息&gt;
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          */
         </span>
        </li>
        <li>
         <span class="keyword">
          static
         </span>
         <span class="keyword">
          class
         </span>
         ConnectionId {
        </li>
        <li class="alt">
         <span class="comment">
          //远程的socket地址
         </span>
        </li>
        <li>
         InetSocketAddress address;
        </li>
        <li class="alt">
         <span class="comment">
          //用户组信息
         </span>
        </li>
        <li>
         UserGroupInformation ticket;
        </li>
        <li class="alt">
         <span class="comment">
          //协议类型
         </span>
        </li>
        <li>
         Class&lt;?&gt; protocol;
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          static
         </span>
         <span class="keyword">
          final
         </span>
         <span class="keyword">
          int
         </span>
         PRIME =
         <span class="number">
          16777619
         </span>
         ;
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         rpcTimeout;
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         String serverPrincipal;
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         maxIdleTime;
         <span class="comment">
          //connections will be culled if it was idle for
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //maxIdleTime msecs
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         maxRetries;
         <span class="comment">
          //the max. no. of retries for socket connections
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          boolean
         </span>
         tcpNoDelay;
         <span class="comment">
          // if T then disable Nagle’s Algorithm
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         pingInterval;
         <span class="comment">
          // how often sends ping to the server in msecs
         </span>
        </li>
        <li class="alt">
         ….
        </li>
       </ol>
       <p>
        这里用了3个属性组成唯一的标识属性，为了保证可以进行ID的复用，所以作者对ConnectionId的equal比较方法和hashCode 进行了重写:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /**
         </span>
        </li>
        <li>
         <span class="comment">
          * 作者重写了equal比较方法，只要成员变量都想等也就想到了
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          */
         </span>
        </li>
        <li>
         <span class="annotation">
          @Override
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          boolean
         </span>
         equals(Object obj) {
        </li>
        <li>
         <span class="keyword">
          if
         </span>
         (obj ==
         <span class="keyword">
          this
         </span>
         ) {
        </li>
        <li class="alt">
         <span class="keyword">
          return
         </span>
         <span class="keyword">
          true
         </span>
         ;
        </li>
        <li>
         }
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (obj
         <span class="keyword">
          instanceof
         </span>
         ConnectionId) {
        </li>
        <li>
         ConnectionId that = (ConnectionId) obj;
        </li>
        <li class="alt">
         <span class="keyword">
          return
         </span>
         isEqual(
         <span class="keyword">
          this
         </span>
         .address, that.address)
        </li>
        <li>
         &amp;&amp;
         <span class="keyword">
          this
         </span>
         .maxIdleTime == that.maxIdleTime
        </li>
        <li class="alt">
         &amp;&amp;
         <span class="keyword">
          this
         </span>
         .maxRetries == that.maxRetries
        </li>
        <li>
         &amp;&amp;
         <span class="keyword">
          this
         </span>
         .pingInterval == that.pingInterval
        </li>
        <li class="alt">
         &amp;&amp; isEqual(
         <span class="keyword">
          this
         </span>
         .protocol, that.protocol)
        </li>
        <li>
         &amp;&amp;
         <span class="keyword">
          this
         </span>
         .rpcTimeout == that.rpcTimeout
        </li>
        <li class="alt">
         &amp;&amp; isEqual(
         <span class="keyword">
          this
         </span>
         .serverPrincipal, that.serverPrincipal)
        </li>
        <li>
         &amp;&amp;
         <span class="keyword">
          this
         </span>
         .tcpNoDelay == that.tcpNoDelay
        </li>
        <li class="alt">
         &amp;&amp; isEqual(
         <span class="keyword">
          this
         </span>
         .ticket, that.ticket);
        </li>
        <li>
         }
        </li>
        <li class="alt">
         <span class="keyword">
          return
         </span>
         <span class="keyword">
          false
         </span>
         ;
        </li>
        <li>
         }
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          /**
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * 重写了hashCode的生成规则，保证不同的对象产生不同的hashCode值
         </span>
        </li>
        <li>
         <span class="comment">
          */
         </span>
        </li>
        <li class="alt">
         <span class="annotation">
          @Override
         </span>
        </li>
        <li>
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          int
         </span>
         hashCode() {
        </li>
        <li class="alt">
         <span class="keyword">
          int
         </span>
         result =
         <span class="number">
          1
         </span>
         ;
        </li>
        <li>
         result = PRIME * result + ((address ==
         <span class="keyword">
          null
         </span>
         ) ?
         <span class="number">
          0
         </span>
         : address.hashCode());
        </li>
        <li class="alt">
         result = PRIME * result + maxIdleTime;
        </li>
        <li>
         result = PRIME * result + maxRetries;
        </li>
        <li class="alt">
         result = PRIME * result + pingInterval;
        </li>
        <li>
         result = PRIME * result + ((protocol ==
         <span class="keyword">
          null
         </span>
         ) ?
         <span class="number">
          0
         </span>
         : protocol.hashCode());
        </li>
        <li class="alt">
         result = PRIME * rpcTimeout;
        </li>
        <li>
         result = PRIME * result
        </li>
        <li class="alt">
         + ((serverPrincipal ==
         <span class="keyword">
          null
         </span>
         ) ?
         <span class="number">
          0
         </span>
         : serverPrincipal.hashCode());
        </li>
        <li>
         result = PRIME * result + (tcpNoDelay ?
         <span class="number">
          1231
         </span>
         :
         <span class="number">
          1237
         </span>
         );
        </li>
        <li class="alt">
         result = PRIME * result + ((ticket ==
         <span class="keyword">
          null
         </span>
         ) ?
         <span class="number">
          0
         </span>
         : ticket.hashCode());
        </li>
        <li>
         <span class="keyword">
          return
         </span>
         result;
        </li>
        <li class="alt">
         }
        </li>
       </ol>
       <p>
        这样就能保证对应同类型的连接就能够完全复用了，而不是仅仅凭借引用的关系判断对象是否相等，这里就是一个不错的设计了。
       </p>
       <p>
        与连接Id对应的就是Connection了，它里面维护是一下的一些变量；
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /** Thread that reads responses and notifies callers.  Each connection owns a
         </span>
        </li>
        <li>
         <span class="comment">
          * socket connected to a remote address.  Calls are multiplexed through this
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * socket: responses may be delivered out of order. */
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          class
         </span>
         Connection
         <span class="keyword">
          extends
         </span>
         Thread {
        </li>
        <li class="alt">
         <span class="comment">
          //所连接的服务器地址
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         InetSocketAddress server;
         <span class="comment">
          // server ip:port
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //服务端的krb5的名字，与安全方面相关
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         String serverPrincipal;
         <span class="comment">
          // server’s krb5 principal name
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //连接头部，内部包含了，所用的协议，客户端用户组信息以及验证的而方法
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         ConnectionHeader header;
         <span class="comment">
          // connection header
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //远程连接ID
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          final
         </span>
         ConnectionId remoteId;
         <span class="comment">
          // connection id
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //连接验证方法
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         AuthMethod authMethod;
         <span class="comment">
          // authentication method
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //下面3个变量都是安全方面的
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          boolean
         </span>
         useSasl;
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         Token&lt;?
         <span class="keyword">
          extends
         </span>
         TokenIdentifier&gt; token;
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         SaslRpcClient saslRpcClient;
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          //下面是一组socket通信方面的变量
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         Socket socket =
         <span class="keyword">
          null
         </span>
         ;
         <span class="comment">
          // connected socket
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         DataInputStream in;
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         DataOutputStream out;
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         rpcTimeout;
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         maxIdleTime;
         <span class="comment">
          //connections will be culled if it was idle for
         </span>
        </li>
        <li>
         <span class="comment">
          //maxIdleTime msecs
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         maxRetries;
         <span class="comment">
          //the max. no. of retries for socket connections
         </span>
        </li>
        <li>
         <span class="comment">
          //tcpNoDelay可设置是否阻塞模式
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          boolean
         </span>
         tcpNoDelay;
         <span class="comment">
          // if T then disable Nagle’s Algorithm
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         pingInterval;
         <span class="comment">
          // how often sends ping to the server in msecs
         </span>
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          // currently active calls 当前活跃的回调，一个连接 可能会有很多个call回调
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         Hashtable&lt;Integer, Call&gt; calls =
         <span class="keyword">
          new
         </span>
         Hashtable&lt;Integer, Call&gt;();
        </li>
        <li>
         <span class="comment">
          //最后一次IO活动通信的时间
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         AtomicLong lastActivity =
         <span class="keyword">
          new
         </span>
         AtomicLong();
         <span class="comment">
          // last I/O activity time
         </span>
        </li>
        <li>
         <span class="comment">
          //连接关闭标记
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         AtomicBoolean shouldCloseConnection =
         <span class="keyword">
          new
         </span>
         AtomicBoolean();
         <span class="comment">
          // indicate if the connection is closed
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         IOException closeException;
         <span class="comment">
          // close reason
         </span>
        </li>
        <li class="alt">
         …..
        </li>
       </ol>
       <p>
        里面维护了大量的和连接通信相关的变量，在这里有一个很有意思的东西connectionHeader，连接头部，里面的数据时为了在通信最开始的时候被使用:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="keyword">
          class
         </span>
         ConnectionHeader
         <span class="keyword">
          implements
         </span>
         Writable {
        </li>
        <li>
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          static
         </span>
         <span class="keyword">
          final
         </span>
         Log LOG = LogFactory.getLog(ConnectionHeader.
         <span class="keyword">
          class
         </span>
         );
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          //客户端和服务端通信的协议名称
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         String protocol;
        </li>
        <li>
         <span class="comment">
          //客户端的用户组信息
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         UserGroupInformation ugi =
         <span class="keyword">
          null
         </span>
         ;
        </li>
        <li>
         <span class="comment">
          //验证的方式，关系到写入数据的时的格式
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         AuthMethod authMethod;
        </li>
        <li>
         …..
        </li>
       </ol>
       <p>
        起到标识验证的作用。一个Client类的基本结构我们基本可以描绘出来了，下面是完整的类关系图:
       </p>
       <p>
        <a href="http://s2.51cto.com/wyfs02/M00/54/85/wKiom1SFThDjVnGNAAGNQh20F6w661.jpg" target="_blank">
         <img src="http://s2.51cto.com/wyfs02/M00/54/85/wKiom1SFThDjVnGNAAGNQh20F6w661.jpg"/>
        </a>
       </p>
       <p>
        在上面这幅图中，你肯定会发现我少了一个很关键的类了，就是Call回调类。Call回调在很多异步通信中是经常出现的。因为在通信过程中，当一个对象通 过网络发送请求给另外一个对象的时候，如果采用同步的方式，会一直阻塞在那里，会带来非常不好的效率和体验的，所以很多时候，我们采用的是一种叫回调接口 的方式。在这期间，用户可以继续做自己的事情。所以同样的Call这个概念当然也是适用在Hadoop RPC中。
        <b>
         在Hadoop的RPC的核心调 用原理， 简单的说，就是我把parame参数序列化到一个对象中，通过参数的形式把对象传入，进行RPC通信，最后服务端把处理好的结果值放入call对象，在返 回给客户端，也就是说客户端和服务端都是通过Call对象进行操作，Call里面存着，请求的参数，和处理后的结构值2个变量。通过Call对象的封装， 客户单实现了完美的无须知道细节的调用。
        </b>
        下面是Call类的类按时：
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /** A call waiting for a value. */
         </span>
        </li>
        <li>
         <span class="comment">
          //客户端的一个回调
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          class
         </span>
         Call {
        </li>
        <li>
         /回调ID
        </li>
        <li class="alt">
         <span class="keyword">
          int
         </span>
         id;
         <span class="comment">
          // call id
         </span>
        </li>
        <li>
         <span class="comment">
          //被序列化的参数
         </span>
        </li>
        <li class="alt">
         Writable param;
         <span class="comment">
          // parameter
         </span>
        </li>
        <li>
         <span class="comment">
          //返回值
         </span>
        </li>
        <li class="alt">
         Writable value;
         <span class="comment">
          // value, null if error
         </span>
        </li>
        <li>
         <span class="comment">
          //出错时返回的异常
         </span>
        </li>
        <li class="alt">
         IOException error;
         <span class="comment">
          // exception, null if value
         </span>
        </li>
        <li>
         <span class="comment">
          //回调是否已经被完成
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          boolean
         </span>
         done;
         <span class="comment">
          // true when call is done
         </span>
        </li>
        <li>
         ….
        </li>
       </ol>
       <p>
        看到这个Call回调类，也许你慢慢的会明白Hadoop RPC的一个基本原型了，这些Call当然是存在于某个连接中的，一个连接可能会发生多个回调，所以在Connection中维护了calls列表：
       </p>
       <ol class="dp-xml">
        <li class="alt">
         private class Connection extends Thread {
        </li>
        <li>
         ….
        </li>
        <li class="alt">
         // currently active calls 当前活跃的回调，一个连接 可能会有很多个call回调
        </li>
        <li>
         private Hashtable
         <span class="tag">
          &lt;
         </span>
         <span class="tag-name">
          Integer
         </span>
         , Call
         <span class="tag">
          &gt;
         </span>
         <span class="attribute">
          calls
         </span>
         =
         <span class="attribute-value">
          new
         </span>
         Hashtable
         <span class="tag">
          &lt;
         </span>
         <span class="tag-name">
          Integer
         </span>
         , Call
         <span class="tag">
          &gt;
         </span>
         ();
        </li>
       </ol>
       <p>
        作者在设计Call类的时候，比较聪明的考虑一种并发情况下的Call调用，所以为此设计了下面这个Call的子类，就是专门用于短时间内的瞬间Call调用:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /** Call implementation used for parallel calls. */
         </span>
        </li>
        <li>
         <span class="comment">
          /** 继承自Call回调类，可以并行的使用，通过加了index下标做Call的区分 */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          class
         </span>
         ParallelCall
         <span class="keyword">
          extends
         </span>
         Call {
        </li>
        <li>
         /每个ParallelCall并行的回调就会有对应的结果类
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         ParallelResults results;
        </li>
        <li>
         <span class="comment">
          //index作为Call的区分
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         index;
        </li>
        <li>
         ….
        </li>
       </ol>
       <p>
        如果要查找值，就通过里面的ParallelCall查找，原理是根据index索引:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /** Result collector for parallel calls. */
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          static
         </span>
         <span class="keyword">
          class
         </span>
         ParallelResults {
        </li>
        <li class="alt">
         <span class="comment">
          //并行结果类中拥有一组返回值，需要ParallelCall的index索引匹配
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         Writable[] values;
        </li>
        <li class="alt">
         <span class="comment">
          //结果值的数量
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         size;
        </li>
        <li class="alt">
         <span class="comment">
          //values中已知的值的个数
         </span>
        </li>
        <li>
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          int
         </span>
         count;
        </li>
        <li class="alt">
        </li>
        <li>
         …..
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          /** Collect a result. */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          synchronized
         </span>
         <span class="keyword">
          void
         </span>
         callComplete(ParallelCall call) {
        </li>
        <li>
         <span class="comment">
          //将call中的值赋给result中
         </span>
        </li>
        <li class="alt">
         values[call.index] = call.value;
         <span class="comment">
          // store the value
         </span>
        </li>
        <li>
         count++;
         <span class="comment">
          // count it
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //如果计数的值等到最终大小，通知caller
         </span>
        </li>
        <li>
         <span class="keyword">
          if
         </span>
         (count == size)
         <span class="comment">
          // if all values are in
         </span>
        </li>
        <li class="alt">
         notify();
         <span class="comment">
          // then notify waiting caller
         </span>
        </li>
        <li>
         }
        </li>
        <li class="alt">
         }
        </li>
       </ol>
       <p>
        因为Call结构集是这些并发Call共有的，所以用的是static变量，都存在在了values数组中了，只有所有的并发Call都把值取出来了，才 算回调成功，这个是个非常细小的辅助设计，这个在有些书籍上并没有多少提及。下面我们看看一般Call回调的流程，正如刚刚说的，最终客户端看到的形式就 是，传入参数，获得结果，忽略内部一切逻辑，这是怎么做到的呢,答案在下面:
       </p>
       <p>
        在执行之前，你会先得到ConnectionId：
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="keyword">
          public
         </span>
         Writable call(Writable param, InetSocketAddress addr,
        </li>
        <li>
         Class&lt;?&gt; protocol, UserGroupInformation ticket,
        </li>
        <li class="alt">
         <span class="keyword">
          int
         </span>
         rpcTimeout)
        </li>
        <li>
         <span class="keyword">
          throws
         </span>
         InterruptedException, IOException {
        </li>
        <li class="alt">
         ConnectionId remoteId = ConnectionId.getConnectionId(addr, protocol,
        </li>
        <li>
         ticket, rpcTimeout, conf);
        </li>
        <li class="alt">
         <span class="keyword">
          return
         </span>
         call(param, remoteId);
        </li>
        <li>
         }
        </li>
       </ol>
       <p>
        接着才是主流程：
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="keyword">
          public
         </span>
         Writable call(Writable param, ConnectionId remoteId)
        </li>
        <li>
         <span class="keyword">
          throws
         </span>
         InterruptedException, IOException {
        </li>
        <li class="alt">
         <span class="comment">
          //根据参数构造一个Call回调
         </span>
        </li>
        <li>
         Call call =
         <span class="keyword">
          new
         </span>
         Call(param);
        </li>
        <li class="alt">
         <span class="comment">
          //根据远程ID获取连接
         </span>
        </li>
        <li>
         Connection connection = getConnection(remoteId, call);
        </li>
        <li class="alt">
         <span class="comment">
          //发送参数
         </span>
        </li>
        <li>
         connection.sendParam(call);
         <span class="comment">
          // send the parameter
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          boolean
         </span>
         interrupted =
         <span class="keyword">
          false
         </span>
         ;
        </li>
        <li>
         <span class="keyword">
          synchronized
         </span>
         (call) {
        </li>
        <li class="alt">
         <span class="comment">
          //如果call.done为false，就是Call还没完成
         </span>
        </li>
        <li>
         <span class="keyword">
          while
         </span>
         (!call.done) {
        </li>
        <li class="alt">
         <span class="keyword">
          try
         </span>
         {
        </li>
        <li>
         <span class="comment">
          //等待远端程序的执行完毕
         </span>
        </li>
        <li class="alt">
         call.wait();
         <span class="comment">
          // wait for the result
         </span>
        </li>
        <li>
         }
         <span class="keyword">
          catch
         </span>
         (InterruptedException ie) {
        </li>
        <li class="alt">
         <span class="comment">
          // save the fact that we were interrupted
         </span>
        </li>
        <li>
         interrupted =
         <span class="keyword">
          true
         </span>
         ;
        </li>
        <li class="alt">
         }
        </li>
        <li>
         }
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          //如果是异常中断，则终止当前线程
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (interrupted) {
        </li>
        <li>
         <span class="comment">
          // set the interrupt flag now that we are done waiting
         </span>
        </li>
        <li class="alt">
         Thread.currentThread().interrupt();
        </li>
        <li>
         }
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          //如果call回到出错，则返回call出错信息
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (call.error !=
         <span class="keyword">
          null
         </span>
         ) {
        </li>
        <li>
         <span class="keyword">
          if
         </span>
         (call.error
         <span class="keyword">
          instanceof
         </span>
         RemoteException) {
        </li>
        <li class="alt">
         call.error.fillInStackTrace();
        </li>
        <li>
         <span class="keyword">
          throw
         </span>
         call.error;
        </li>
        <li class="alt">
         }
         <span class="keyword">
          else
         </span>
         {
         <span class="comment">
          // local exception
         </span>
        </li>
        <li>
         <span class="comment">
          // use the connection because it will reflect an ip change, unlike
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          // the remoteId
         </span>
        </li>
        <li>
         <span class="keyword">
          throw
         </span>
         wrapException(connection.getRemoteAddress(), call.error);
        </li>
        <li class="alt">
         }
        </li>
        <li>
         }
         <span class="keyword">
          else
         </span>
         {
        </li>
        <li class="alt">
         <span class="comment">
          //如果是正常情况下，返回回调处理后的值
         </span>
        </li>
        <li>
         <span class="keyword">
          return
         </span>
         call.value;
        </li>
        <li class="alt">
         }
        </li>
        <li>
         }
        </li>
        <li class="alt">
         }
        </li>
       </ol>
       <p>
        在这上面的操作步骤中，重点关注2个函数，获取连接操作，看看人家是如何保证连接的复用性的:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="keyword">
          private
         </span>
         Connection getConnection(ConnectionId remoteId,
        </li>
        <li>
         Call call)
        </li>
        <li class="alt">
         <span class="keyword">
          throws
         </span>
         IOException, InterruptedException {
        </li>
        <li>
         …..
        </li>
        <li class="alt">
         <span class="comment">
          /* we could avoid this allocation for each RPC by having a
         </span>
        </li>
        <li>
         <span class="comment">
          * connectionsId object and with set() method. We need to manage the
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * refs for keys in HashMap properly. For now its ok.
         </span>
        </li>
        <li>
         <span class="comment">
          */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          do
         </span>
         {
        </li>
        <li>
         <span class="keyword">
          synchronized
         </span>
         (connections) {
        </li>
        <li class="alt">
         <span class="comment">
          //从connection连接池中获取连接，可以保证相同的连接ID可以复用
         </span>
        </li>
        <li>
         connection = connections.get(remoteId);
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (connection ==
         <span class="keyword">
          null
         </span>
         ) {
        </li>
        <li>
         connection =
         <span class="keyword">
          new
         </span>
         Connection(remoteId);
        </li>
        <li class="alt">
         connections.put(remoteId, connection);
        </li>
        <li>
         }
        </li>
        <li class="alt">
         }
        </li>
        <li>
         }
         <span class="keyword">
          while
         </span>
         (!connection.addCall(call));
        </li>
       </ol>
       <p>
        有点单例模式的味道哦，还有一个方法叫sendParam发送参数方法:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="keyword">
          public
         </span>
         <span class="keyword">
          void
         </span>
         sendParam(Call call) {
        </li>
        <li>
         <span class="keyword">
          if
         </span>
         (shouldCloseConnection.get()) {
        </li>
        <li class="alt">
         <span class="keyword">
          return
         </span>
         ;
        </li>
        <li>
         }
        </li>
        <li class="alt">
        </li>
        <li>
         DataOutputBuffer d=
         <span class="keyword">
          null
         </span>
         ;
        </li>
        <li class="alt">
         <span class="keyword">
          try
         </span>
         {
        </li>
        <li>
         <span class="keyword">
          synchronized
         </span>
         (
         <span class="keyword">
          this
         </span>
         .out) {
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (LOG.isDebugEnabled())
        </li>
        <li>
         LOG.debug(getName() +
         <span class="string">
          ” sending #”
         </span>
         + call.id);
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          //for serializing the
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          //data to be written
         </span>
        </li>
        <li>
         <span class="comment">
          //将call回调中的参数写入到输出流中，传向服务端
         </span>
        </li>
        <li class="alt">
         d =
         <span class="keyword">
          new
         </span>
         DataOutputBuffer();
        </li>
        <li>
         d.writeInt(call.id);
        </li>
        <li class="alt">
         call.param.write(d);
        </li>
        <li>
         <span class="keyword">
          byte
         </span>
         [] data = d.getData();
        </li>
        <li class="alt">
         <span class="keyword">
          int
         </span>
         dataLength = d.getLength();
        </li>
        <li>
         out.writeInt(dataLength);
         <span class="comment">
          //first put the data length
         </span>
        </li>
        <li class="alt">
         out.write(data,
         <span class="number">
          0
         </span>
         , dataLength);
         <span class="comment">
          //write the data
         </span>
        </li>
        <li>
         out.flush();
        </li>
        <li class="alt">
         }
        </li>
        <li>
         ….
        </li>
       </ol>
       <p>
        代码只发送了Call的id，和请求参数，并没有把所有的Call的内容都扔出去了，一定是为了减少数据量的传输，这里还把数据的长度写入了，这是为了方 便服务端准确的读取到不定长的数据。这服务端中间的处理操作不是今天讨论的重点。Call的执行过程就是这样。那么Call是如何被调用的呢，这又要重新 回到了Client客户端上去了，Client有一个run()函数，所有的操作都是始于此的；
       </p>
       <ol class="dp-xml">
        <li class="alt">
         public void run() {
        </li>
        <li>
         if (LOG.isDebugEnabled())
        </li>
        <li class="alt">
         LOG.debug(getName() + “: starting, having connections “
        </li>
        <li>
         + connections.size());
        </li>
        <li class="alt">
        </li>
        <li>
         //等待工作，等待请求调用
        </li>
        <li class="alt">
         while (waitForWork()) {//wait here for work – read or close connection
        </li>
        <li>
         //调用完请求，则立即获取回复
        </li>
        <li class="alt">
         receiveResponse();
        </li>
        <li>
         }
        </li>
        <li class="alt">
        </li>
        <li>
         close();
        </li>
        <li class="alt">
        </li>
        <li>
         if (LOG.isDebugEnabled())
        </li>
        <li class="alt">
         LOG.debug(getName() + “: stopped, remaining connections “
        </li>
        <li>
         + connections.size());
        </li>
        <li class="alt">
         }
        </li>
       </ol>
       <p>
        操作很简单，程序一直跑着，有请求，处理请求，获取请求，没有请求，就死等。
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          synchronized
         </span>
         <span class="keyword">
          boolean
         </span>
         waitForWork() {
        </li>
        <li>
         <span class="keyword">
          if
         </span>
         (calls.isEmpty() &amp;&amp; !shouldCloseConnection.get()  &amp;&amp; running.get())  {
        </li>
        <li class="alt">
         <span class="keyword">
          long
         </span>
         timeout = maxIdleTime-
        </li>
        <li>
         (System.currentTimeMillis()-lastActivity.get());
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (timeout&gt;
         <span class="number">
          0
         </span>
         ) {
        </li>
        <li>
         <span class="keyword">
          try
         </span>
         {
        </li>
        <li class="alt">
         wait(timeout);
        </li>
        <li>
         }
         <span class="keyword">
          catch
         </span>
         (InterruptedException e) {}
        </li>
        <li class="alt">
         }
        </li>
        <li>
         }
        </li>
        <li class="alt">
         ….
        </li>
       </ol>
       <p>
        获取回复的操作如下:
       </p>
       <ol class="dp-j">
        <li class="alt">
         <span class="comment">
          /* Receive a response.
         </span>
        </li>
        <li>
         <span class="comment">
          * Because only one receiver, so no synchronization on in.
         </span>
        </li>
        <li class="alt">
         <span class="comment">
          * 获取回复值
         </span>
        </li>
        <li>
         <span class="comment">
          */
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          private
         </span>
         <span class="keyword">
          void
         </span>
         receiveResponse() {
        </li>
        <li>
         <span class="keyword">
          if
         </span>
         (shouldCloseConnection.get()) {
        </li>
        <li class="alt">
         <span class="keyword">
          return
         </span>
         ;
        </li>
        <li>
         }
        </li>
        <li class="alt">
         <span class="comment">
          //更新最近一次的call活动时间
         </span>
        </li>
        <li>
         touch();
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="keyword">
          try
         </span>
         {
        </li>
        <li class="alt">
         <span class="keyword">
          int
         </span>
         id = in.readInt();
         <span class="comment">
          // try to read an id
         </span>
        </li>
        <li>
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (LOG.isDebugEnabled())
        </li>
        <li>
         LOG.debug(getName() +
         <span class="string">
          ” got value #”
         </span>
         + id);
        </li>
        <li class="alt">
        </li>
        <li>
         <span class="comment">
          //从获取call中取得相应的call
         </span>
        </li>
        <li class="alt">
         Call call = calls.get(id);
        </li>
        <li>
        </li>
        <li class="alt">
         <span class="comment">
          //判断该结果状态
         </span>
        </li>
        <li>
         <span class="keyword">
          int
         </span>
         state = in.readInt();
         <span class="comment">
          // read call status
         </span>
        </li>
        <li class="alt">
         <span class="keyword">
          if
         </span>
         (state == Status.SUCCESS.state) {
        </li>
        <li>
         Writable value = ReflectionUtils.newInstance(valueClass, conf);
        </li>
        <li class="alt">
         value.readFields(in);
         <span class="comment">
          // read value
         </span>
        </li>
        <li>
         call.setValue(value);
        </li>
        <li class="alt">
         calls.remove(id);
        </li>
        <li>
         }
         <span class="keyword">
          else
         </span>
         <span class="keyword">
          if
         </span>
         (state == Status.ERROR.state) {
        </li>
        <li class="alt">
         call.setException(
         <span class="keyword">
          new
         </span>
         RemoteException(WritableUtils.readString(in),
        </li>
        <li>
         WritableUtils.readString(in)));
        </li>
        <li class="alt">
         calls.remove(id);
        </li>
        <li>
         }
         <span class="keyword">
          else
         </span>
         <span class="keyword">
          if
         </span>
         (state == Status.FATAL.state) {
        </li>
        <li class="alt">
         <span class="comment">
          // Close the connection
         </span>
        </li>
        <li>
         markClosed(
         <span class="keyword">
          new
         </span>
         RemoteException(WritableUtils.readString(in),
        </li>
        <li class="alt">
         WritableUtils.readString(in)));
        </li>
        <li>
         }
        </li>
        <li class="alt">
         …..
        </li>
        <li>
         }
         <span class="keyword">
          catch
         </span>
         (IOException e) {
        </li>
        <li class="alt">
         markClosed(e);
        </li>
        <li>
         }
        </li>
        <li class="alt">
         }
        </li>
       </ol>
       <p>
        从之前维护的Call列表中取出，做判断。Client本身的执行流程比较的简单:
       </p>
       <p>
        <a href="http://s6.51cto.com/wyfs02/M00/54/85/wKiom1SFT8qjZdRwAAF81v3vN5g558.jpg" target="_blank">
         <img src="http://s6.51cto.com/wyfs02/M00/54/85/wKiom1SFT8qjZdRwAAF81v3vN5g558.jpg"/>
        </a>
       </p>
       <p>
        Hadoop RPC客户端的通信模块的部分大致就是我上面的这个流程，中间其实还忽略了很多的细节，大家学习的时候，针对源码会有助于更好的理解，Hadoop RPC的服务端的实现更加复杂，所以建议采用分模块的学习或许会更好一点。
       </p>
       <p>
        本文出自：
        <a href="http://blog.csdn.net/Androidlushangderen/article/details/41751133">
         http://blog.csdn.net/Androidlushangderen/article/details/41751133
        </a>
       </p>
      </div>
      <div>
       <strong>
        注：转载文章均来自于公开网络，仅供学习使用，不会用于任何商业用途，如果侵犯到原作者的权益，请您与我们联系删除或者授权事宜，联系邮箱：contact@dataunion.org。转载数盟网站文章请注明原文章作者，否则产生的任何版权纠纷与数盟无关。
       </strong>
      </div>
      <!--content_text-->
      <div class="fenxian">
       <!-- JiaThis Button BEGIN -->
       <div class="jiathis_style_32x32">
        <p class="jiathis_button_weixin">
        </p>
        <p class="jiathis_button_tsina">
        </p>
        <p class="jiathis_button_qzone">
        </p>
        <p class="jiathis_button_cqq">
        </p>
        <p class="jiathis_button_tumblr">
        </p>
        <a class="jiathis jiathis_txt jtico jtico_jiathis" href="http://www.jiathis.com/share" target="_blank">
        </a>
        <p class="jiathis_counter_style">
        </p>
       </div>
       <!-- JiaThis Button END -->
      </div>
     </article>
     <!--content-->
     <!--相关文章-->
     <div class="xianguan">
      <div class="xianguantitle">
       相关文章！
      </div>
      <ul class="pic">
       <li>
        <a href="http://dataunion.org/20638.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/09/t013908f7a9eec17a28_副本-300x206.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/20638.html" rel="bookmark" title="大家都不炒了，预示着Hadoop已经达到预期的成熟度？">
         大家都不炒了，预示着Hadoop已经达到预期的成熟度？
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/20412.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/08/u25379030543345962768fm21gp0.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/20412.html" rel="bookmark" title="把 Hadoop 装进大脑的15种方式！">
         把 Hadoop 装进大脑的15种方式！
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/20040.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/07/QQ截图20150719153031.png"/>
        </a>
        <a class="link" href="http://dataunion.org/20040.html" rel="bookmark" title="Twitter核心数据类库团队的Hadoop优化经验">
         Twitter核心数据类库团队的Hadoop优化经验
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/19954.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/07/t01e28e0ec2882d1b22_副本_副本.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/19954.html" rel="bookmark" title="微博广告推荐中有关Hadoop的那些事">
         微博广告推荐中有关Hadoop的那些事
        </a>
       </li>
      </ul>
     </div>
     <!--相关文章-->
     <div class="comment" id="comments">
      <!-- You can start editing here. -->
      <!-- If comments are open, but there are no comments. -->
      <div class="title">
       期待你一针见血的评论，Come on！
      </div>
      <div id="respond">
       <p>
        不用想啦，马上
        <a href="http://dataunion.org/wp-login.php?redirect_to=http%3A%2F%2Fdataunion.org%2F3225.html">
         "登录"
        </a>
        发表自已的想法.
       </p>
      </div>
     </div>
     <!-- .nav-single -->
    </div>
    <!--Container End-->
    <aside id="sitebar">
     <div class="sitebar_list2">
      <div class="wptag">
       <span class="tagtitle">
        热门标签+
       </span>
       <div class="tagg">
        <ul class="menu" id="menu-%e5%8f%8b%e6%83%85%e9%93%be%e6%8e%a5">
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1605" id="menu-item-1605">
          <a href="http://taidizh.com/">
           泰迪智慧
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-20884" id="menu-item-20884">
          <a href="http://www.transwarp.cn/">
           星环科技
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-3538" id="menu-item-3538">
          <a href="http://datall.org/">
           珈和遥感
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-20888" id="menu-item-20888">
          <a href="http://www.chinahadoop.cn/">
           小象学院
          </a>
         </li>
        </ul>
       </div>
      </div>
     </div>
     <div class="sitebar_list">
      <div class="textwidget">
       <div align="center">
        <a href="http://study.163.com/course/courseMain.htm?courseId=991022" target="_blank">
         <img src="http://dataunion.org/wp-content/uploads/2016/03/dv.jpg"/>
        </a>
       </div>
      </div>
     </div>
     <div class="sitebar_list">
      <h4 class="sitebar_title">
       文章分类
      </h4>
      <div class="tagcloud">
       <a class="tag-link-44" href="http://dataunion.org/category/industry/demo" style="font-size: 10.204724409449pt;" title="4个话题">
        Demo展示
       </a>
       <a class="tag-link-31" href="http://dataunion.org/category/experts" style="font-size: 15.826771653543pt;" title="52个话题">
        专家团队
       </a>
       <a class="tag-link-870" href="http://dataunion.org/category/tech/ai" style="font-size: 19.795275590551pt;" title="273个话题">
        人工智能
       </a>
       <a class="tag-link-488" href="http://dataunion.org/category/%e5%8a%a0%e5%85%a5%e6%95%b0%e7%9b%9f" style="font-size: 8pt;" title="1个话题">
        加入数盟
       </a>
       <a class="tag-link-869" href="http://dataunion.org/category/tech/viz" style="font-size: 17.204724409449pt;" title="93个话题">
        可视化
       </a>
       <a class="tag-link-30" href="http://dataunion.org/category/partners" style="font-size: 10.645669291339pt;" title="5个话题">
        合作伙伴
       </a>
       <a class="tag-link-889" href="http://dataunion.org/category/parterc" style="font-size: 11.582677165354pt;" title="8个话题">
        合作会议
       </a>
       <a class="tag-link-104" href="http://dataunion.org/category/books" style="font-size: 12.96062992126pt;" title="15个话题">
        图书
       </a>
       <a class="tag-link-220" href="http://dataunion.org/category/tech/base" style="font-size: 19.850393700787pt;" title="281个话题">
        基础架构
       </a>
       <a class="tag-link-219" href="http://dataunion.org/category/tech/analysis" style="font-size: 19.409448818898pt;" title="232个话题">
        数据分析
       </a>
       <a class="tag-link-887" href="http://dataunion.org/category/tech/dm" style="font-size: 13.291338582677pt;" title="17个话题">
        数据挖掘
       </a>
       <a class="tag-link-34" href="http://dataunion.org/category/tech" style="font-size: 20.732283464567pt;" title="404个话题">
        文章
       </a>
       <a class="tag-link-1" href="http://dataunion.org/category/uncategorized" style="font-size: 22pt;" title="693个话题">
        未分类
       </a>
       <a class="tag-link-4" href="http://dataunion.org/category/events" style="font-size: 14.503937007874pt;" title="29个话题">
        活动
       </a>
       <a class="tag-link-890" href="http://dataunion.org/category/tech/%e6%b7%b1%e5%ba%a6%e5%ad%a6%e4%b9%a0" style="font-size: 10.204724409449pt;" title="4个话题">
        深度学习
       </a>
       <a class="tag-link-221" href="http://dataunion.org/category/tech/devl" style="font-size: 18.968503937008pt;" title="193个话题">
        编程语言
       </a>
       <a class="tag-link-888" href="http://dataunion.org/category/career" style="font-size: 15.661417322835pt;" title="48个话题">
        职业规划
       </a>
       <a class="tag-link-5" href="http://dataunion.org/category/jobs" style="font-size: 14.11811023622pt;" title="25个话题">
        职位
       </a>
       <a class="tag-link-871" href="http://dataunion.org/category/industry" style="font-size: 15.716535433071pt;" title="49个话题">
        行业
       </a>
       <a class="tag-link-613" href="http://dataunion.org/category/industry/case" style="font-size: 16.984251968504pt;" title="84个话题">
        行业应用
       </a>
       <a class="tag-link-885" href="http://dataunion.org/category/industry/news" style="font-size: 17.425196850394pt;" title="102个话题">
        行业资讯
       </a>
       <a class="tag-link-10" href="http://dataunion.org/category/training" style="font-size: 14.228346456693pt;" title="26个话题">
        课程
       </a>
       <a class="tag-link-16" href="http://dataunion.org/category/sources" style="font-size: 15.661417322835pt;" title="48个话题">
        资源
       </a>
      </div>
     </div>
     <div class="sitebar_list">
      <h4 class="sitebar_title">
       功能
      </h4>
      <ul>
       <li>
        <a href="http://dataunion.org/wp-login.php?action=register">
         注册
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/wp-login.php">
         登录
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/feed">
         文章
         <abbr title="Really Simple Syndication">
          RSS
         </abbr>
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/comments/feed">
         评论
         <abbr title="Really Simple Syndication">
          RSS
         </abbr>
        </a>
       </li>
       <li>
        <a href="https://cn.wordpress.org/" title="基于WordPress，一个优美、先进的个人信息发布平台。">
         WordPress.org
        </a>
       </li>
      </ul>
     </div>
    </aside>
    <div class="clear">
    </div>
   </div>
   <!--main-->
   ﻿
   <footer id="dibu">
    <div class="about">
     <div class="right">
      <ul class="menu" id="menu-%e5%ba%95%e9%83%a8%e8%8f%9c%e5%8d%95">
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18024" id="menu-item-18024">
        <a href="http://dataunion.org/category/partners">
         合作伙伴
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20881" id="menu-item-20881">
        <a href="http://dataunion.org/contribute">
         文章投稿
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20872" id="menu-item-20872">
        <a href="http://dataunion.org/category/%e5%8a%a0%e5%85%a5%e6%95%b0%e7%9b%9f">
         加入数盟
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22441" id="menu-item-22441">
        <a href="http://dataunion.org/f-links">
         友情链接
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20874" id="menu-item-20874">
        <a href="http://dataunion.org/aboutus">
         关于数盟
        </a>
       </li>
      </ul>
      <p class="banquan">
       数盟社区        ，
        做最棒的数据科学社区
      </p>
     </div>
     <div class="left">
      <ul class="bottomlist">
       <li>
        <a href="http://weibo.com/DataScientistUnion  " target="_blank" 　title="">
         <img src="http://dataunion.org/wp-content/themes/yzipi/images/weibo.png"/>
        </a>
       </li>
       <li>
        <a class="cd-popup-trigger" href="http://dataunion.org/3225.html#0">
         <img src="http://dataunion.org/wp-content/themes/yzipi/images/weixin.png"/>
        </a>
       </li>
      </ul>
      <div class="cd-popup">
       <div class="cd-popup-container">
        <h1>
         扫描二维码,加微信公众号
        </h1>
        <img src="http://dataunion.org/wp-content/themes/yzipi/images/2014-12-06-1515289049.png"/>
        <a class="cd-popup-close" href="http://dataunion.org/3225.html">
        </a>
       </div>
       <!-- cd-popup-container -->
      </div>
      <!-- cd-popup -->
     </div>
    </div>
    <!--about-->
    <div class="bottom">
     <a href="http://dataunion.org/">
      数盟社区
     </a>
     <a href="http://www.miitbeian.gov.cn/" rel="external nofollow" target="_blank">
      京ICP备14026740号
     </a>
     联系我们：
     <a href="mailto:contact@dataunion.org" target="_blank">
      contact@dataunion.org
     </a>
     <div class="tongji">
     </div>
     <!--bottom-->
     <div class="scroll" id="scroll" style="display:none;">
      ︿
     </div>
    </div>
   </footer>
   <!--dibu-->
  </div>
 </body>
</html>